package main

import (
	"bufio"
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/libp2p/go-libp2p"

	"github.com/libp2p/go-libp2p/core/crypto"
	"github.com/libp2p/go-libp2p/core/network"
	"github.com/libp2p/go-libp2p/core/peer"

	ma "github.com/multiformats/go-multiaddr"
)

func main() {
	// 创建自己的私钥，并且指定监听模式以及端口生成libp2p节点
	keyReader := strings.NewReader("00000000000000000000000000000002")

	privateKey, _, err := crypto.GenerateEd25519Key(keyReader)

	if err != nil {
		panic(err)
	}
	// 创建节点
	managerNode, err := libp2p.New(
		libp2p.Identity(privateKey),
		libp2p.NoListenAddrs,
		// Usually EnableRelay() is not required as it is enabled by default
		// but NoListenAddrs overrides this, so we're adding it in explictly again.
		libp2p.EnableRelay(),
	)

	if err != nil {
		log.Printf("创建节点失败: %v", err)
		return
	}

	defer managerNode.Close()

	// 生成地址
	relayServerID := "12D3KooWBgGF8kGMbuDjXJ4ya1RZX479VNS4sfoATXWBNLha2b5G"
	addr := "/ip4/127.0.0.1/tcp/8520"
	relayAddrStr := fmt.Sprintf("%s/p2p/%s", addr, relayServerID)
	relayAddr, err := ma.NewMultiaddr(relayAddrStr)
	if err != nil {
		log.Printf("地址格式化失败: %v", err)
		return
	}

	relayInfo, err := peer.AddrInfoFromP2pAddr(relayAddr)
	if err != nil {
		log.Printf("地址转换失败: %v", err)
		return
	}

	// 连接远程服务器
	if err := managerNode.Connect(context.Background(), *relayInfo); err != nil {
		log.Printf("连接远程服务器失败: %v", err)
		return
	}

	// // 启动本地服务，允许其他节点连接
	// _, err = client.Reserve(context.Background(), clientNode, *relayInfo)
	// if err != nil {
	// 	log.Printf("本地服务启动失败: %v", err)
	// 	return
	// }

	log.Printf("节点ID: %s", managerNode.ID())

	targetId := "12D3KooWBnTyEyBVeYpZJobw78rb85nNamrYQR3Tc6gJmfQ76pG4"
	targetAddrStr := "/p2p/" + relayInfo.ID.String() + "/p2p-circuit/p2p/" + targetId
	targetAddr, err := ma.NewMultiaddr(targetAddrStr)
	if err != nil {
		log.Println(err)
		return
	}

	targetInfo, err := peer.AddrInfoFromP2pAddr(targetAddr)
	if err != nil {
		log.Printf("拨号失败: %v", err)
		return
	}

	if err := managerNode.Connect(context.Background(), *targetInfo); err != nil {
		log.Printf("连接目标节点失败: %v", err)
		return
	}

	log.Println("连接目标节点成功")

	stream, err := managerNode.NewStream(network.WithUseTransient(context.Background(), "chatStream"), targetInfo.ID, "/chatStream")
	if err != nil {
		log.Println("创建聊天通道失败: ", err)
		return
	}

	defer stream.Close()

	rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))

	go writeData(rw)
	go readData(rw)

	select {}
}

func readData(rw *bufio.ReadWriter) {
	for {
		str, err := rw.ReadString('\n')

		if err != nil {
			log.Println(err)
			return
		}

		if str == "" {
			return
		}

		if str != "\n" {
			log.Print(str)
			fmt.Print(">")
		}
	}
}

func writeData(rw *bufio.ReadWriter) {
	stdReader := bufio.NewReader(os.Stdin)

	for {
		fmt.Print(">")
		sendData, err := stdReader.ReadString('\n')
		if err != nil {
			log.Println(err)
			return
		}

		rw.WriteString(fmt.Sprintf("%s\n", sendData))
		rw.Flush()
	}
}
